package apple.eclipse.actions;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Iterator;

import org.eclipse.jface.action.Action;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.ui.INullSelectionListener;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction;

import apple.core.Apple;
import apple.eclipse.model.Model;

public abstract class AbstractStatusAction extends Action implements
      IWorkbenchAction, INullSelectionListener, PropertyChangeListener {

   private IWorkbenchWindow window;

   private IStructuredSelection structuredSelection;

   public AbstractStatusAction(IWorkbenchWindow window) {
      this.window = window;
      setEnabled(false);
      window.getSelectionService().addSelectionListener(this);
      Model model = Model.getInstance();
      model.addPropertyChangeListener(new PropertyChangeListener() {
         public void propertyChange(PropertyChangeEvent event) {
            if (event.getPropertyName().equals(Model.PROPERTY_NAME)) {
               Apple apple = (Apple) event.getSource();
               if (event.getNewValue() != null && event.getOldValue() == null) {
                  apple.addPropertyChangeListener(AbstractStatusAction.this);
               } else if (event.getNewValue() == null
                     && event.getOldValue() != null) {
                  apple.removePropertyChangeListener(AbstractStatusAction.this);
               } else {
                  assert false;
               }
            }
         }
      });
   }

   public void run() {
      Iterator iterator = structuredSelection.iterator();
      while (iterator.hasNext()) {
         Apple apple = (Apple) iterator.next();
         runAction(apple);
      }
   }

   public void selectionChanged(IWorkbenchPart part, ISelection selection) {
      if (selection instanceof IStructuredSelection) {
         structuredSelection = (IStructuredSelection) selection;
      } else {
         structuredSelection = null;
      }
      boolean valid = checkSelection();
      setEnabled(valid);
   }

   public void propertyChange(PropertyChangeEvent event) {
      if (event.getPropertyName().equals(Apple.PROPERTY_NAME)) {
         Apple apple = (Apple) event.getSource();
         if (!enablementCondition(apple)) {
            setEnabled(false);
         } else {
            boolean valid = checkSelection();
            setEnabled(valid);
         }
      }
   }

   private boolean checkSelection() {
      boolean valid = false;
      if (structuredSelection != null && structuredSelection.size() > 0) {
         valid = true;
         Iterator iterator = structuredSelection.iterator();
         while (iterator.hasNext()) {
            Object object = iterator.next();
            if (object instanceof Apple) {
               Apple apple = (Apple) object;
               if (!enablementCondition(apple)) {
                  valid = false;
                  break;
               }
            } else {
               valid = false;
               break;
            }
         }
      }
      return valid;
   }

   abstract protected boolean enablementCondition(Apple apple);

   abstract protected void runAction(Apple apple);

   public void dispose() {
      window.getSelectionService().removeSelectionListener(this);
   }
}
